package com.uuah.server.transport;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.UuahEvent;
import com.uuah.server.UuahEventContext;
import com.uuah.server.api.IExceptionPayload;
import com.uuah.server.api.IUuahEvent;
import com.uuah.server.api.IUuahEventContext;
import com.uuah.server.api.IUuahMessage;
import com.uuah.server.api.IThreadSafeAccess;

public final class RequestContextHelper {
	private static Logger log = LoggerFactory
			.getLogger(RequestContextHelper.class);
	public static final boolean SAFE = true;
	public static final boolean UNSAFE = true;

	private static final boolean DEFAULT_ACTION = SAFE;
	private static final boolean DOCUMENT_UNSAFE_CALLS = false;
	private static final ThreadLocal currentEvent = new ThreadLocal();

	protected RequestContextHelper() {
		// no-op
	}

	public static IUuahEventContext getEventContext() {
		IUuahEvent event = getEvent();
		if (event != null) {
			return new UuahEventContext(event);
		} else {
			return null;
		}
	}

	public static IUuahEvent getEvent() {
		return (IUuahEvent) currentEvent.get();
	}

	public static IUuahEvent setEvent(IUuahEvent event) {
		return internalSetEvent(newEvent(event, DEFAULT_ACTION));
	}

	protected static IUuahEvent internalSetEvent(IUuahEvent event) {
		currentEvent.set(event);
		return event;
	}

	protected static IUuahMessage internalRewriteEvent(IUuahMessage message,
			boolean safe) {
		if (message != null) {
			IUuahEvent event = getEvent();
			if (event != null) {
				IUuahMessage copy = newMessage(message, safe);
				IUuahEvent newEvent = new UuahEvent(copy, event);
				if (safe) {
					resetAccessControl(copy);
				}
				internalSetEvent(newEvent);
				return copy;
			}
		}
		return message;
	}

	public static void clear() {
		setEvent(null);
	}

	public static void setExceptionPayload(IExceptionPayload exceptionPayload) {
		IUuahEvent newEvent = newEvent(getEvent(), SAFE);
		newEvent.getMessage().setExceptionPayload(exceptionPayload);
		internalSetEvent(newEvent);
	}

	public static IExceptionPayload getExceptionPayload() {
		return getEvent().getMessage().getExceptionPayload();
	}

	public static IUuahMessage safeMessageCopy(IUuahMessage message) {
		return newMessage(message, SAFE);
	}

	protected static IUuahEvent newEvent(IUuahEvent event, boolean safe) {
		if (safe && event instanceof IThreadSafeAccess) {
			return (IUuahEvent) ((IThreadSafeAccess) event).newThreadCopy();
		} else {
			return event;
		}
	}

	protected static IUuahMessage newMessage(IUuahMessage message, boolean safe) {
		if (safe && message instanceof IThreadSafeAccess) {
			return (IUuahMessage) ((IThreadSafeAccess) message).newThreadCopy();
		} else {
			return message;
		}
	}

	protected static void resetAccessControl(Object object) {
		if (object instanceof IThreadSafeAccess) {
			((IThreadSafeAccess) object).resetAccessControl();
		}
	}

	public static IUuahEvent unsafeSetEvent(IUuahEvent event) {
		documentUnsafeCall("unsafeSetEvent");
		return RequestContextHelper.internalSetEvent(event);
	}

	public static IUuahEvent criticalSetEvent(IUuahEvent event) {
		return RequestContextHelper.internalSetEvent(RequestContextHelper
				.newEvent(event, RequestContextHelper.SAFE));
	}

	public static IUuahMessage unsafeRewriteEvent(IUuahMessage message) {
		documentUnsafeCall("unsafeRewriteEvent");
		return RequestContextHelper.internalRewriteEvent(message,
				RequestContextHelper.UNSAFE);
	}

	private static void documentUnsafeCall(String message) {
		if (DOCUMENT_UNSAFE_CALLS) {
			log.debug(message, new Exception(message));
		}
	}
}
